/*
 * The contents of this web application are subject to the Mozilla Public License Version 
 * 1.1 (the "License"); you may not use this web application except in compliance with 
 * the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the License.
 * 
 * The Original Code is owned by and the Initial Developer of the Original Code is 
 * Composite A/S (Danish business reg.no. 21744409). All Rights Reserved
 * 
 * Section 11 of the License is EXPRESSLY amended to include a provision stating 
 * that any dispute, including but not limited to disputes related to the enforcement 
 * of the License, to which Composite A/S as owner of the Original Code, as Initial 
 * Developer or in any other role, becomes a part to shall be governed by Danish law 
 * and be initiated before the Copenhagen City Court ("K�benhavns Byret")            
 */

using System;
using System.Collections.Generic;
using System.Linq;
using Composite.C1Console.Actions;
using Composite.C1Console.Events;
using Composite.Core;
using Composite.Data;
using Composite.Data.DynamicTypes;
using Composite.Data.ExtendedDataType.Debug;
using Composite.Data.GeneratedTypes;
using Composite.C1Console.Security;
using Composite.Core.Types;
using Composite.C1Console.Users;
using Composite.Data.Validation.ClientValidationRules;
using Composite.C1Console.Workflow;
using Composite.Plugins.Elements.ElementProviders.Common;
using Texts = Composite.Core.ResourceSystem.LocalizationFiles.Composite_Plugins_GeneratedDataTypesElementProvider;

namespace Composite.Plugins.Elements.ElementProviders.GeneratedDataTypesElementProvider
{
    [AllowPersistingWorkflow(WorkflowPersistingType.Idle)]
    public sealed partial class AddNewInterfaceTypeWorkflow : Composite.C1Console.Workflow.Activities.FormsWorkflow
    {
        public AddNewInterfaceTypeWorkflow()
        {
            InitializeComponent();
        }

        private static class BindingNames
        {
            public const string InternalUrlPrefix = "InternalUrlPrefix";
            public const string KeyFieldType = "KeyFieldType";
            public const string KeyFieldTypeOptions = "KeyFieldTypeOptions";
            public const string KeyFieldReadOnly = "KeyFieldReadOnly";
        }

        private void initialStateCodeActivity_ExecuteCode(object sender, EventArgs e)
        {
            this.Bindings = new Dictionary<string, object>
            {
                {"ViewLabel", Texts.AddNewInterfaceTypeStep1_DocumentTitle},
                {"NewTypeName", ""},
                {"NewTypeNamespace", UserSettings.LastSpecifiedNamespace},
                {"NewTypeTitle", ""},
                {"DataFieldDescriptors", new List<DataFieldDescriptor>()},
                {"HasCaching", false},
                {"HasPublishing", false},
                {"HasLocalization", false},
                {"LabelFieldName", ""},
                {BindingNames.KeyFieldType, GeneratedTypesHelper.KeyFieldType.Guid.ToString()},
                {BindingNames.KeyFieldTypeOptions, KeyFieldHelper.GetKeyFieldOptions()},
                {BindingNames.KeyFieldReadOnly, false}
            };

            this.BindingsValidationRules = new Dictionary<string, List<ClientValidationRule>>
            {
                {"NewTypeName", new List<ClientValidationRule> {new NotNullClientValidationRule()}},
                {"NewTypeNamespace", new List<ClientValidationRule> {new NotNullClientValidationRule()}},
                {"NewTypeTitle", new List<ClientValidationRule> {new NotNullClientValidationRule()}}
            };

            if (RuntimeInformation.IsDebugBuild && DynamicTempTypeCreator.UseTempTypeCreator)
            {
                var dynamicTempTypeCreator = new DynamicTempTypeCreator("GlobalTest");

                this.UpdateBinding("NewTypeName", dynamicTempTypeCreator.TypeName);
                this.UpdateBinding("NewTypeTitle", dynamicTempTypeCreator.TypeTitle);
                this.UpdateBinding("DataFieldDescriptors", dynamicTempTypeCreator.DataFieldDescriptors);

                this.UpdateBinding("LabelFieldName", dynamicTempTypeCreator.DataFieldDescriptors.First().Name);
            }
        }



        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
            try
            {
                string typeName = this.GetBinding<string>("NewTypeName");
                string typeNamespace = this.GetBinding<string>("NewTypeNamespace");
                string typeTitle = this.GetBinding<string>("NewTypeTitle");
                bool hasCaching = this.GetBinding<bool>("HasCaching");
                bool hasPublishing = this.GetBinding<bool>("HasPublishing");
                bool hasLocalization = this.GetBinding<bool>("HasLocalization");
                string labelFieldName = this.GetBinding<string>("LabelFieldName");
                string internalUrlPrefix = this.GetBinding<string>(BindingNames.InternalUrlPrefix);
                var dataFieldDescriptors = this.GetBinding<List<DataFieldDescriptor>>("DataFieldDescriptors");

                var keyFieldType = KeyFieldHelper.ParseKeyFieldType(GetBinding<string>(BindingNames.KeyFieldType));


                GeneratedTypesHelper helper;
                Type interfaceType = null;
                if (this.BindingExist("InterfaceType"))
                {
                    interfaceType = this.GetBinding<Type>("InterfaceType");

                    helper = new GeneratedTypesHelper(interfaceType);
                }
                else
                {
                    helper = new GeneratedTypesHelper();
                    helper.SetKeyFieldType(keyFieldType);
                }

                string errorMessage;
                if (!helper.ValidateNewTypeName(typeName, out errorMessage))
                {
                    this.ShowFieldMessage("NewTypeName", errorMessage);
                    return;
                }

                if (!helper.ValidateNewTypeNamespace(typeNamespace, out errorMessage))
                {
                    this.ShowFieldMessage("NewTypeNamespace", errorMessage);
                    return;
                }

                if (!helper.ValidateNewTypeFullName(typeName, typeNamespace, out errorMessage))
                {
                    this.ShowFieldMessage("NewTypeName", errorMessage);
                    return;
                }

                if (!helper.ValidateNewFieldDescriptors(dataFieldDescriptors, out errorMessage))
                {
                    this.ShowMessage(
                            DialogType.Warning,
                            Texts.AddNewInterfaceTypeStep1_ErrorTitle,
                            errorMessage
                        );
                    return;
                }

                if(interfaceType != null)
                {
                    if(hasLocalization != DataLocalizationFacade.IsLocalized(interfaceType)
                        && DataFacade.GetData(interfaceType).ToDataEnumerable().Any())
                    {
                        this.ShowMessage(
                            DialogType.Error,
                            Texts.AddNewInterfaceTypeStep1_ErrorTitle,
                            "It's not possible to change localization through the current tab"
                        );
                        return;             
                    }
                }


                if (helper.IsEditProcessControlledAllowed)
                {
                    helper.SetCachable(hasCaching);
                    helper.SetPublishControlled(hasPublishing);
                    helper.SetLocalizedControlled(hasLocalization);
                }   

                helper.SetNewTypeFullName(typeName, typeNamespace);
                helper.SetNewTypeTitle(typeTitle);
                helper.SetNewInternalUrlPrefix(internalUrlPrefix);
                helper.SetNewFieldDescriptors(dataFieldDescriptors, labelFieldName);

                bool originalTypeDataExists = false;
                if (interfaceType != null)
                {
                    originalTypeDataExists = DataFacade.HasDataInAnyScope(interfaceType);
                }

                if (!helper.TryValidateUpdate(originalTypeDataExists, out errorMessage))
                {
                    this.ShowMessage(
                            DialogType.Warning,
                            Texts.AddNewInterfaceTypeStep1_ErrorTitle,
                            errorMessage
                        );
                    return;
                }


                helper.CreateType(originalTypeDataExists);

                string serializedTypeName = TypeManager.SerializeType(helper.InterfaceType);

                EntityToken entityToken = new GeneratedDataTypesElementProviderTypeEntityToken(
                    serializedTypeName, 
                    this.EntityToken.Source, 
                    GeneratedDataTypesElementProviderRootEntityToken.GlobalDataTypeFolderId);

                if(originalTypeDataExists)
                {
                    SetSaveStatus(true);
                }
                else
                {
                    SetSaveStatus(true, entityToken);
                }
                

                if (!this.BindingExist("InterfaceType"))
                {                    
                    this.AcquireLock(entityToken);
                }

                this.UpdateBinding("InterfaceType", helper.InterfaceType);
                this.UpdateBinding(BindingNames.KeyFieldReadOnly, true);

                this.UpdateBinding("ViewLabel", typeTitle);
                RerenderView();

                UserSettings.LastSpecifiedNamespace = typeNamespace;

                ParentTreeRefresher parentTreeRefresher = this.CreateParentTreeRefresher();
                parentTreeRefresher.PostRefreshMesseges(this.EntityToken, 2);

                
               
            }
            catch (Exception ex)
            {
                Log.LogCritical("Add New Interface Failed", ex);

                this.ShowMessage(DialogType.Error, "Error", ex.Message);
            }
        }
    }
}
